package fussbudget;

import interfaces.IcanHandleTransactions;

import java.awt.datatransfer.DataFlavor;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.Enumeration;
import java.util.LinkedHashMap;

import org.jdesktop.swingx.treetable.MutableTreeTableNode;

import fussbudget.SQL.FBSQL;
import fussbudget.SQL.SQLUtility;
import fussbudget.abstracts.AbstractDraggableElement;
import fussbudget.gui.CalendarMaster;

public class PaymentEntity extends AbstractDraggableElement implements IcanHandleTransactions {
	public enum Type {
		UNDEFINED,
		ROOT,
		GROUP,
		PAYER,
		PAYEE
	}

	private String					accountID		= "";
	private String					phoneNumber		= "";
	private Address					address			= new Address();
	private boolean					isPayee			= false;
	private boolean					isPayer			= false;
	public static final DataFlavor	dataFlavor		= new DataFlavor(PaymentEntity.class, "PaymentEntity");
	// public int categoryID;

	private ArrayList<Transaction>	transactions	= new ArrayList<Transaction>();

	public PaymentEntity(ResultSet rs) {
		try {
			id = rs.getInt("id");
			isGroup = rs.getBoolean("isGroup");
			name = rs.getString("name");
			accountID = rs.getString("accountID");
			phoneNumber = rs.getString("phoneNumber");
			address = new Address(rs.getString("address"));
			isPayee = rs.getBoolean("isPayee");
			isPayer = rs.getBoolean("isPayer");
			SQLUtility.lock();
			parentElement = new PaymentEntity("temp", EnumSet.of(Type.GROUP));
			parentElement.setId(rs.getInt("parentEntity"));
			SQLUtility.unlock();

			addToCalendar();
			addToSets();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	public PaymentEntity(String name, EnumSet<PaymentEntity.Type> types) {
		this.name = name;
		if (!types.equals(EnumSet.of(Type.UNDEFINED))) {
			id = FBSQL.addPaymentEntity(this);

			if (types.equals(EnumSet.of(Type.ROOT))) {
				setGroup(true);
			} else if (types.equals(EnumSet.of(Type.PAYER, Type.GROUP))) {
				setGroup(true);
				setPayer(true);
			} else if (types.equals(EnumSet.of(Type.PAYEE, Type.GROUP))) {
				setGroup(true);
				setPayee(true);
			} else if (types.equals(EnumSet.of(Type.PAYER))) {
				setPayer(true);
			} else if (types.equals(EnumSet.of(Type.PAYEE))) {
				setPayee(true);
			}
			addToCalendar();
		}
		addToSets();
	}

	
	public void setParentElement(PaymentEntity newParent) {
		super.setParentElement(newParent);
		CalendarMaster.setParentGroup(this, newParent);
	}

	public void addToCalendar() {
		if (isGroup) {
			if (isPayer) {
				CalendarMaster.addIncomeGroup(this);
			} else if (isPayee) {
				CalendarMaster.addExpensesGroup(this);
			}
		}
	}

	public void addToSets() {
		if(FussBudgetMain.payeeSet!=null && FussBudgetMain.payerSet!=null && FussBudgetMain.allEntitySet!=null)
		if (!isGroup) {
			if (isPayee) {
				FussBudgetMain.payeeSet.addEntity(this);
			} else if (isPayer) {
				FussBudgetMain.payerSet.addEntity(this);
			}
			FussBudgetMain.allEntitySet.addEntity(this);
		}
	}

	public synchronized void delete() {
		Enumeration<? extends MutableTreeTableNode> kids = this.children();
		while (kids.hasMoreElements()) {
			((PaymentEntity) kids.nextElement()).delete();
		}

		CalendarMaster.removeGroup(this);
		
		if(FussBudgetMain.payeeSet.contains(this)){
			FussBudgetMain.payeeSet.remove(this);
		}
		if(FussBudgetMain.payerSet.contains(this)){
			FussBudgetMain.payerSet.remove(this);
		}
		
		FBSQL.removeElement("paymentEntity", "id=" + id);
	}

	public synchronized void setName(String name) {
		super.setName(name);
		CalendarMaster.renameGroup(id, name);
		FBSQL.alterString("paymentEntity", "name", name, id);
	}

	public synchronized String getAccountID() {
		return accountID;
	}

	public synchronized void setAccountID(String accountID) {
		this.accountID = accountID;
		FBSQL.alterString("paymentEntity", "account", accountID, id);
	}

	public synchronized String getPhoneNumber() {
		return phoneNumber;
	}

	public synchronized void setPhoneNumber(String phoneNumber) {
		this.phoneNumber = phoneNumber;
		FBSQL.alterString("paymentEntity", "phoneNumber", phoneNumber, id);
	}

	public synchronized Address getAddress() {
		return address;
	}

	public synchronized void setAddress(Address address) {
		this.address = address;
		FBSQL.alterString("paymentEntity", "address", address.toSQL(), id);
	}

	public boolean isGroup() {
		return isGroup;
	}

	public void setGroup(boolean isGroup) {
		this.isGroup = isGroup;
		FBSQL.alterBoolean("paymentEntity", "isGroup", isGroup, id);
	}

	public boolean isPayee() {
		return isPayee;
	}

	public void setPayee(boolean isPayee) {
		this.isPayee = isPayee;
		FBSQL.alterBoolean("paymentEntity", "isPayee", isPayee, id);
	}

	public boolean isPayer() {
		return isPayer;
	}

	public void setPayer(boolean isPayer) {
		this.isPayer = isPayer;
		FBSQL.alterBoolean("paymentEntity", "isPayer", isPayer, id);
	}

	public void setParentElement(AbstractDraggableElement parentElement) {
		super.setParentElement(parentElement);
		FBSQL.alterInt("paymentEntity", "parentEntity", parentElement.getId(), id);
	}

	public ArrayList<Transaction> getTransactions() {
		return transactions;
	}

	public void setTransactions(ArrayList<Transaction> transactions) {
		this.transactions = transactions;
		// TODO
	}

	@Override
	public boolean getAllowsChildren() {
		return isGroup;
	}

	public void add(MutableTreeTableNode child) {
		super.add(child);
		((PaymentEntity) child).setParentElement(this);
	}

	/*
	 * (non-Javadoc)
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((accountID == null) ? 0 : accountID.hashCode());
		result = prime * result + ((address == null) ? 0 : address.hashCode());
		result = prime * result + (isPayee ? 1231 : 1237);
		result = prime * result + (isPayer ? 1231 : 1237);
		result = prime * result + ((phoneNumber == null) ? 0 : phoneNumber.hashCode());
		result = prime * result + ((transactions == null) ? 0 : transactions.hashCode());
		return result;
	}

	/*
	 * (non-Javadoc)
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		PaymentEntity other = (PaymentEntity) obj;
		if (accountID == null) {
			if (other.accountID != null)
				return false;
		} else if (!accountID.equals(other.accountID))
			return false;
		if (address == null) {
			if (other.address != null)
				return false;
		} else if (!address.equals(other.address))
			return false;
		if (isPayee != other.isPayee)
			return false;
		if (isPayer != other.isPayer)
			return false;
		if (phoneNumber == null) {
			if (other.phoneNumber != null)
				return false;
		} else if (!phoneNumber.equals(other.phoneNumber))
			return false;
		if (transactions == null) {
			if (other.transactions != null)
				return false;
		} else if (!transactions.equals(other.transactions))
			return false;
		return true;
	}

}